package ai.tuobot.sdk

import ai.tuobot.sdk.model.AudioConfig
import ai.tuobot.sdk.model.MsgMonitor
import ai.tuobot.sdk.util.CircularBuffer
import ai.tuobot.sdk.util.ConfigToObj
import ai.tuobot.sdk.util.LocalSTT
import ai.tuobot.sdk.util.ProcessTextEvent
import ai.tuobot.sdk.util.StringUtil
import ai.tuobot.sdk.util.WordsMatch
import android.os.Bundle
import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import org.junit.Assert.*
import org.junit.Test
import java.io.InputStream
import java.util.Locale

/**
 * Instrumented test, which will execute on an Android device.
 *
 * See [testing documentation](http://d.android.com/tools/testing).
 */

class ExampleInstrumentedTest {
    private val TAG = "ExampleInstrumentedTest"
    val jsonString = """
            {
                "session": {
                    "llm_model": "rebyte",
                    "use_search": "false",
                    "use_quivr": "false",
                    "is_journal_mode": "false",
                    "token": ""
                },
                "userparams": {
                    "access_token": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
                    "device_id": 1,
                    "family_id": 2
                }
            }
        """.trimIndent()

    @Test
    fun useAppContext() {
        // Context of the app under test.
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        assertEquals("ai.tuobot.app.test", appContext.packageName)
    }

    @Test
    fun jsonTest(){
        val jsonPeace = StringUtil.getJsonPeaceByAndWithTag("userparams", jsonString)
        val campareStr = "{\"userparams\":{\"access_token\":\"xxxxxxxxxxxxxxxxxxxxxxxxxx\",\"device_id\":1,\"family_id\":2}}".trimIndent()

        assertEquals(jsonPeace,campareStr)


        var preJsonStr = """[event]:[
            {
                "event_type": "sensitive_words",
                "words":["敏感词1","敏感词2"],
                "intent ":null
            },{
                "event_type": "wake_up",
                "intent ":null
            },{
                "event_type": "nlp",
                    "intent": {
                        "intent_name": "create_schedule_in",
                        "intent_type": "custom",
                        "rc": 0
                    }
                }
        ]"""


        // 截取 `[event]:` 后面的部分
        var result = preJsonStr.substringAfter("[event]:")

        // 转换为 JSONArray
        var eventConJsonArr = JSONArray(result)


        assertEquals(eventConJsonArr.length(),3)

        for (i in 0 until eventConJsonArr.length()) {
            val jsonObj = eventConJsonArr.get(i)

            val eventType = (jsonObj as JSONObject).getString("event_type")

            when (eventType) {
                "sensitive_words" -> {
                    println("识别到敏感词")
                }
                "wake_up" -> {
                    println("识别到唤醒")
                }
                "nlp" -> {
                    println("识别到语义事件")
                }
            }

        }

        ////////////////

        try {
            preJsonStr = """[event]: [{"event_type": "wake_up", "intent": null}] """
            // 截取 `[event]:` 后面的部分
            result = preJsonStr.substringAfter("[event]:")
            // 转换为 JSONArray
            eventConJsonArr = JSONArray(result)
            for (i in 0 until eventConJsonArr.length()) {
                val jsonObj = eventConJsonArr.get(i)

                val eventType = (jsonObj as JSONObject).getString("event_type")

                when (eventType) {
                    "sensitive_words" -> {
                        println("识别到敏感词")
                    }
                    "wake_up" -> {
                        println("识别到唤醒")
                    }
                    "nlp" -> {
                        println("识别到语义事件")
                    }
                }

            }
        } catch (e: JSONException) {
            Log.e(TAG,e.message.toString())
            // 处理 JSON 解析异常
            e.printStackTrace()
        } catch (e: Exception) {
            Log.e(TAG,e.message.toString())
            // 处理其他异常
            e.printStackTrace()
        }

    }

    @Test
    fun testJsonToData(){
        var jsonString:String = """
            {"audio":{
                "auto_play": true,
                "volume_threshold": 3600,
                "end_listen_silence_time": 600,
                "break_llm_say": false,
                "format": "mp3",
                "ANS": false
            }}
        """
        var cfgJson: JSONObject? = null

        cfgJson = jsonString?.let { JSONObject(it) }
        val newAudioConfig = ConfigToObj.cfgJsonToAudioConfig(cfgJson)
        val newAudioConfigStr = "AudioConfig(auto_play=true, volume_threshold=3600, end_listen_silence_time=600, break_llm_say=false, format=mp3, ANS=false)"
        assertEquals(newAudioConfigStr,newAudioConfig.toString())
        assertEquals(newAudioConfig,AudioConfig())
    }

    @Test
    fun testJsonToData2(){
        var jsonString:String = """
            {"audio":{
                "auto_play": false,
                "volume_threshold": 3600,
                "end_listen_silence_time": 600,
                "break_llm_say": false,
                "format": "mp3",
                "ANS": false
            }}
        """
        var cfgJson: JSONObject? = null

        cfgJson = jsonString?.let { JSONObject(it) }
        val newAudioConfig = ConfigToObj.cfgJsonToAudioConfig(cfgJson)
        val newAudioConfigStr = "AudioConfig(auto_play=false, volume_threshold=3600, end_listen_silence_time=600, break_llm_say=false, format=mp3, ANS=false)"
        assertEquals(newAudioConfigStr,newAudioConfig.toString())
        assertNotEquals(newAudioConfig,AudioConfig())
    }

    @Test
    fun CircularBuffer_Test(){
        val circularBuffer = CircularBuffer(10)
        val dataToWrite = ByteArray(5)
        dataToWrite.fill(1)
        circularBuffer.write(dataToWrite)

        val outputData = ByteArray(5)
        var bytesRead = circularBuffer.read(outputData, 5)
        var outputDataString = outputData.joinToString(", ") { it.toString() }

        assertEquals(true,bytesRead > 0)
        assertEquals("1, 1, 1, 1, 1", outputDataString)


        dataToWrite.fill(2)
        circularBuffer.write(dataToWrite)

        bytesRead = circularBuffer.read(outputData, 5)
        outputDataString = outputData.joinToString(", ") { it.toString() }
        assertEquals(true,bytesRead > 0)
        assertEquals("2, 2, 2, 2, 2", outputDataString)

        //////////////////start

        bytesRead = circularBuffer.read(outputData, 1)
        assertEquals(false,bytesRead > 0)
        //////////////////end

        ///////////////////start
        val dataToWrite3 = ByteArray(3)
        dataToWrite3[0] = 1
        dataToWrite3[1] = 2
        dataToWrite3[2] = 3
        circularBuffer.write(dataToWrite3)

        bytesRead = circularBuffer.read(outputData, 3)
        outputDataString = outputData.joinToString(", ") { it.toString() }
        assertEquals(true,bytesRead > 0)
        assertEquals("1, 2, 3, 2, 2", outputDataString)
        //////////////////end

        ///////////////////start
        assertEquals(true,circularBuffer.isEmpty())
        ///////////////////end

        ///////////////////start
        val dataToWrite4 = ByteArray(12)
        dataToWrite4.fill(8)
        dataToWrite4[9] = 5
        dataToWrite4[10] = 3
        dataToWrite4[11] = 4
        circularBuffer.write(dataToWrite4)

        val outputData2 = ByteArray(10)
        bytesRead = circularBuffer.read(outputData2, 10)
        outputDataString = outputData2.joinToString(", ") { it.toString() }
        assertEquals(true,bytesRead > 0)
        assertEquals("8, 8, 8, 8, 8, 8, 8, 5, 3, 4", outputDataString)
        //////////////////end

        ///////////////////start
        assertEquals(true,circularBuffer.isEmpty())
        ///////////////////end


        ///////////////////start
        val dataToWrite5 = ByteArray(48000)
        dataToWrite5.fill(6)
        circularBuffer.write(dataToWrite5)

        bytesRead = circularBuffer.read(outputData2, 5)
        outputDataString = outputData2.joinToString(", ") { it.toString() }
        assertEquals(true,bytesRead > 0)
        assertEquals("6, 6, 6, 6, 6, 8, 8, 5, 3, 4", outputDataString)
        //////////////////end

    }

    /********************************************************************************/
    // Since TuoBotSdk1.6
    /********************************************************************************/

    @Test
    fun MsgMonitor_Test(): Unit = runBlocking {
        launch (Dispatchers.Main){
            val wakeUpMsg = MsgMonitor.monitorWakeUpMsg()
            var result = ProcessTextEvent.processEvent(wakeUpMsg)
            assertEquals(MsgMonitor.TYPE_WAKE_UP,result.first)

            val sleepMsg = MsgMonitor.monitorSleepMsg()
            result = ProcessTextEvent.processEvent(sleepMsg)
            assertEquals(MsgMonitor.TYPE_SLEEP,result.first)

            val bundle = Bundle()
            bundle.putString("text", MsgMonitor.monitorWakeUpMsg())

            var bundleText = bundle.getString("text")

            val regex = Regex("""\[event\]:\s*(\[.*\])""")
            val matchResult = bundleText?.let { regex.find(it) }
            assertEquals(true,matchResult!=null)
        }
    }


    @Test
    fun LocalSTT_Test(): Unit = runBlocking {
        launch (Dispatchers.Main){
            val appContext = InstrumentationRegistry.getInstrumentation().targetContext
            val localSTT = LocalSTT(appContext)
            assertEquals(LocalSTT.STATE_READY, localSTT.initModel())

            //Alice
            var ais: InputStream = appContext.getAssets().open("Name_Alice.wav")

            var recMapRes = localSTT.recognizeFile(ais)

            assertEquals(true, WordsMatch.matching("alice",recMapRes))
            assertEquals(true, WordsMatch.matching("Alice",recMapRes))

            //Amy
            ais = appContext.getAssets().open("Name_Amy.wav")

            recMapRes = localSTT.recognizeFile(ais)

            assertEquals(false, WordsMatch.matching("alice",recMapRes))

        }
    }



}